package com.demo.spring.enable.async2.core;

import java.lang.annotation.Annotation;
import java.util.concurrent.Executor;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.scheduling.annotation.AbstractAsyncConfiguration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.config.TaskManagementConfigUtils;

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTracerAsyncConfiguration extends AbstractAsyncConfiguration {

	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		this.enableAsync = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTracerAsync.class.getName(), false));
		if (this.enableAsync == null) {
			throw new IllegalArgumentException("@EnableTracerAsync is not present on importing class " + importMetadata.getClassName());
		}
	}

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TracerAsyncAnnotationBeanPostProcessor asyncAdvisor() {
		TracerAsyncAnnotationBeanPostProcessor bpp = new TracerAsyncAnnotationBeanPostProcessor();
		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableTracerAsync.class, "annotation")) {
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
		bpp.setExecutor(asyncExecutor());
		if (this.exceptionHandler != null) {
			bpp.setExceptionHandler(this.exceptionHandler);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}

	@Bean("tracerAsyncThreadPool")
	public Executor asyncExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		int core = Runtime.getRuntime().availableProcessors();
		taskExecutor.setCorePoolSize(core);//线程池维护线程的最少数量
		taskExecutor.setMaxPoolSize(core << 2);//线程池维护线程的最大数量
		taskExecutor.setQueueCapacity(core << 4);//线程池所使用的缓冲队列
		taskExecutor.initialize();
		return taskExecutor;
	}

}
